// by Xeno

d_misc_stores = "Land_HelipadEmpty_F" createVehicleLocal [0,0,0];

XfStoreAdd = {d_misc_stores setVariable [_this select 0, _this select 1]};
XfStoreGet = {d_misc_stores getVariable _this};

["EAST", east] call XfStoreAdd;
["WEST", west] call XfStoreAdd;
["GUER", resistance] call XfStoreAdd;
["CIV", civilian] call XfStoreAdd;

x_creategroup = {
	private ["_found_empty","_grp","_i","_side","_side_str","_this","_tmp_grp","_tmp_grp_a","_tmp_time","_x"];
	_side = _this select 0;
	_side_str = if (typeName _side == "STRING") then {_side call XfStoreGet} else {_side};
	_grp = createGroup _side_str;
	_grp setVariable ["X_CREATED", time + 120];
	_grp setVariable ["D_SMOKEUNITS", []];
	_grp
};

x_getwparray = {
	private["_tc", "_radius","_wp_a","_point"];
	_tc = _this select 0;_radius = _this select 1;_wp_a = [];_wp_a resize 100;
	for "_i" from 0 to 99 do {
		_point = [_tc, _radius] call XfGetRanPointCircle;
		while {count _point == 0} do {_point = [_pos_center, _radius] call XfGetRanPointCircle};
		_wp_a set [_i, _point];
	};
	_wp_a
};

x_getwparray2 = {
	private["_tc", "_radius","_wp_a","_point"];
	_tc = _this select 0;_radius = _this select 1;_wp_a = [];_wp_a resize 100;
	for "_i" from 0 to 99 do {
		_point = [_tc, _radius] call XfGetRanPointCircleOuter;
		while {count _point == 0} do {_point = [_tc, _radius] call XfGetRanPointCircleOuter};
		_wp_a set [_i, _point];
	};
	_wp_a
};

x_getwparray3 = {
	private ["_pos","_a","_b","_angle","_wp_a","_point"];
	_pos = _this select 0;_a = _this select 1;_b = _this select 2;_angle = _this select 3;_wp_a = [];_wp_a resize 100;
	for "_i" from 0 to 99 do {
		_point = [_pos, _a, _b, _angle] call XfGetRanPointSquare;
		while {count _point == 0} do {_point = [_pos, _a, _b, _angle] call XfGetRanPointSquare};
		_wp_a set [_i, _point];
	};
	_wp_a
};

x_getunitliste = {
	private ["_grptype","_how_many","_list","_one_man","_random","_side","_side_char","_unitliste","_vehiclename","_varray"];
	_grptype = _this select 0;_side = _this select 1;_unitliste = [];_vehiclename = "";_varray = [];
	_side_char = if (typeName _side == "STRING") then {
		switch (_side) do {case "EAST": {"E"};case "WEST": {"W"};case "GUER": {"G"};case "CIV": {"W"};}
	} else {
		switch (_side) do {case east: {"E"};case west: {"W"};case resistance: {"G"};case civilian: {"W"};}
	};
	switch (_grptype) do {
		case "basic": {_list = missionNamespace getVariable format ["d_allmen_%1",_side_char];_unitliste = _list call XfRandomArrayVal};
		case "specops": {_how_many = ceil random 5; if (_how_many < 2) then {_how_many = 2};_list = missionNamespace getVariable format ["d_specops_%1",_side_char];_unitliste resize _how_many;for "_i" from 0 to _how_many - 1 do {_unitliste set [_i, _list call XfRandomArrayVal]}};
		case "artiobserver": {_unitliste = [missionNamespace getVariable format["d_arti_observer_%1",_side_char]]};
		case "heli": {_list = missionNamespace getVariable format ["d_allmen_%1",_side_char];_unitliste = _list call XfRandomArrayVal};
		case "tank": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 0;_vehiclename = _varray call XfRandomArrayVal};
		case "bmp": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 1;_vehiclename = _varray call XfRandomArrayVal};
		case "brdm": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 2;_vehiclename = _varray call XfRandomArrayVal};
		case "shilka": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 3;_vehiclename = _varray call XfRandomArrayVal};
		case "uaz_mg": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 4;_vehiclename = _varray call XfRandomArrayVal};
		case "uaz_grenade": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 5;_vehiclename = _varray call XfRandomArrayVal};
		case "static": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 6;_vehiclename = _varray call XfRandomArrayVal};
		case "igla": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 7;_vehiclename = _varray call XfRandomArrayVal};
		case "D30": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 8;_vehiclename = _varray call XfRandomArrayVal};
		case "uralfuel": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 9;_vehiclename = _varray call XfRandomArrayVal};
		case "uralrep": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 10;_vehiclename = _varray call XfRandomArrayVal};
		case "uralammo": {_varray = (missionNamespace getVariable format ["d_veh_a_%1", _side_char]) select 11;_vehiclename = _varray call XfRandomArrayVal};
		case "civilian": {_unitliste resize 12; for "_i" from 0 to 11 do {_one_man = d_civilians_t call XfRandomArrayVal;_unitliste set [_i,_one_man]}};
		case "sabotage": {_how_many = ceil random 12; if (_how_many < 6) then {_how_many = 6};_list = missionNamespace getVariable format ["d_sabotage_%1",_side_char];_unitliste resize _how_many; for "_i" from 0 to _how_many - 1 do {_unitliste set [_i, _list call XfRandomArrayVal]}};
	};
	[_unitliste, _vehiclename]
};

x_getmixedliste = {
	private ["_side", "_ret_list", "_list"];
	_side = _this select 0;
	_ret_list = [];
	{
		_list = [_x,_side] call x_getunitliste;
		_ret_list set [count _ret_list, [_list select 1, _list select 2]];
	} forEach [switch (floor random 2) do {case 0: {"brdm"};case 1: {"uaz_mg"};}, "bmp", "tank", "shilka"];
	_ret_list
};

XfAddToCleanUp = {

};


// TODO: Add some code which will launch smoke from the vehicle when hit.
XfCallSmoke2 = { 
	private ["_vec","_damage","_smokeshell","_pos","_last_smoke"];
	diag_log Format["Launching smoke: %1", _this];
	// [unit, causedBy, damage]
	_vec = _this select 0;
	_damage = _this select 2;
	
	if (_damage > 0.02) then {
		_last_smoke = _vec getVariable "LastSmokeShell";
		if (isnil "_last_smoke") then { _last_smoke = 0; };
		if ((time - _last_smoke) > 60 && (speed _vec) <= 1) then {
			_pos = _vec modelToWorld [5,5,0];
			_smokeshell = "SmokeShell" CreateVehicle _pos;
			_smokeshell setDamage 1;
			_pos = _vec modelToWorld [-5,5,0];
			_smokeshell = "SmokeShell" CreateVehicle _pos;
			_smokeshell setDamage 1;
			_pos = _vec modelToWorld [5,-5,0];
			_smokeshell = "SmokeShell" CreateVehicle _pos;
			_smokeshell setDamage 1;
			_pos = _vec modelToWorld [-5,-5,0];
			_smokeshell = "SmokeShell" CreateVehicle _pos;
			_smokeshell setDamage 1;
			_pos = _vec modelToWorld [8,0,0];
			_smokeshell = "SmokeShell" CreateVehicle _pos;
			_smokeshell setDamage 1;
			_pos = _vec modelToWorld [-8,0,0];
			_smokeshell = "SmokeShell" CreateVehicle _pos;
			_smokeshell setDamage 1;
			_pos = _vec modelToWorld [0,8,0];
			_smokeshell = "SmokeShell" CreateVehicle _pos;
			_smokeshell setDamage 1;
			_pos = _vec modelToWorld [0,-8,0];
			_smokeshell = "SmokeShell" CreateVehicle _pos;
			_smokeshell setDamage 1;
			_vec setVariable ["LastSmokeShell", time];
		};
	};
};

XfHasSmokeLauncher = {
	private ["_ret", "_configT", "_config2", "_config", "_weapons"];
	_ret = false;
	_configT = (configFile >> "CfgVehicles" >> typeOf _this >> "Turrets");
	if (count _configT > 0) then {
		_config2 = ((_configT select 0) >> "Turrets");
		if (count _config2 > 0) then {
			_config = _config2 select 0;
			_weapons = getArray(_config >> "weapons");
			if ("SmokeLauncher" in _weapons) then {_ret = true};
		};
	};
	_ret
};

XfGetUnitSkill = {
	(d_skill_array select 0) + (random (d_skill_array select 1))
};

XfGetGroupSkill = {
	private ["_vehiclename"];
	_vehiclename = vehicle (leader _this);
	if (_vehiclename in ["M2StaticMG","AGS","M119","D30_RU","DSHkM_Mini_TriPod","Stinger_Pod_East","TOW_TriPod_East","M2HD_mini_TriPod","MK19_TriPod","Stinger_Pod","TOW_Tripod"]) then {1.0} else {call XfGetUnitSkill}
};

// Creates a group of vehicle. 
x_makevgroup = {
	private ["_numbervehicles", "_pos", "_vehiclename", "_grp", "_radius", "_direction", "_crews", "_grpskill", "_n", "_dir", "_vehicle", "_npos"];
	_numbervehicles = _this select 0;
	_pos = _this select 1;
	_vehiclename = _this select 2;
	_grp = _this select 3;
	_radius = _this select 4;
	_direction = _this select 5;
	_do_points = if (count _this > 6) then {true} else {false};
	_the_vehicles = [];
	_crews = [];
	_npos = _pos;
	
	_grpskill = if (_vehiclename in ["M2StaticMG","AGS","M119","D30_RU","DSHkM_Mini_TriPod","Stinger_Pod_East","TOW_TriPod_East","M2HD_mini_TriPod","MK19_TriPod","Stinger_Pod","TOW_Tripod"]) then {1.0} else {(d_skill_array select 0) + (random (d_skill_array select 1))};
	
	// Spawns each vehicle and add the necessary eventHandlers and make them locked or not following the config.
	_the_vehicles resize _numbervehicles;
	for "_n" from 0 to _numbervehicles - 1 do {
		_dir = if (_direction != -1.111) then {_direction} else {floor random 360};
		
		_vec_array = [_npos, _dir, _vehiclename, _grp] call XfSpawnVehicle;
		_vehicle = _vec_array select 0;
		_crews = [_crews, (_vec_array select 1)] call XfArrayPushStack;
		
		_the_vehicles set [_n, _vehicle];
		_npos = _vehicle modelToWorld [0,-12,0];
		
		switch (true) do {
			case (_vehicle isKindOf "Tank"): {
				if (d_smoke) then {if (_vehicle call XfHasSmokeLauncher) then {_vehicle addEventHandler ["hit", {_this spawn XfCallSmoke2}]}};
				if (d_LockArmored == 0) then {_vehicle lock true};
			};
			case (_vehicle isKindOf "Car"): {
				if (d_smoke) then {if (_vehicle isKindOf "Wheeled_APC") then {if (_vehicle call XfHasSmokeLauncher) then {_vehicle addEventHandler ["hit", {_this spawn XfCallSmoke2}]}}};
				if (d_LockCars == 0) then {_vehicle lock true};
			};
			default {
				if (_vehicle isKindOf "Air") then {if (d_LockAir == 0) then {_vehicle lock true}};
			};
		};
	};
	(leader _grp) setSkill _grpskill;
	[_the_vehicles, _crews]
};

// TODO: Add some code to handle this.
XfDoSmoke1 = { diag_log "Footmen smoke launch";};

XfDoSmokeAddCheck = {
	private ["_unit", "_grp", "_mags"];
	_unit = _this select 0;
	_grp = _this select 1;
	_mags = magazines _unit;
	if ("SmokeShellRed" in _mags || "SmokeShellGreen" in _mags || "SmokeShell" in _mags) then {
		_sar = _grp getVariable "D_SMOKEUNITS";
		_sar set [count _sar, _unit];
	};
	_unit setVariable ["D_KIL_EH_SM", _unit addEventHandler ["killed", {_this spawn XfDoSmoke1}]];
};

x_makemgroup = {
	private ["_pos", "_unitliste", "_grp", "_ret"];
	_pos = _this select 0;_unitliste = _this select 1;_grp = _this select 2;_ret = [];
	{
		_one_unit = [_x, _grp, _pos, 10] call XfCreateUnit;
		// _one_unit = _grp createunit [_x, _pos, [], 10,"NONE"];
		_one_unit setVariable ["BIS_noCoreConversations", true];
		// TODO: Reenable it later and see how to set it right.
		// if (d_smoke) then {[_one_unit, _grp] call XfDoSmokeAddCheck};
		_one_unit setUnitAbility ((d_skill_array select 0) + (random (d_skill_array select 1)));
		_ret set [count _ret, _one_unit];
	} foreach _unitliste;
	(leader _grp) setRank "SERGEANT";
	_ret
};

XCreateInf = {
	private ["_radius", "_pos", "_nr", "_nrg", "_typenr", "_i", "_newgroup", "_units"];
	_pos_center = _this select 4;
	_radius = _this select 5;
	_do_patrol = (if (count _this == 7) then {_this select 6} else {false});
	if (_radius < 50) then {_do_patrol = false};

	_ret_grps = [];
	_pos = [];

	for "_nr" from 0 to 1 do {
		_nrg = _this select (1 + (_nr * 2));
		if (_nrg > 0) then {
			_typenr = _this select (_nr * 2);
			for "_i" from 1 to _nrg do {
				_newgroup = [d_side_enemy] call x_creategroup;
				_unit_array = [_typenr, d_enemy_side] call x_getunitliste;
				if (_radius > 0) then {
					_pos = [_pos_center, _radius] call XfGetRanPointCircle;
					while {count _pos == 0} do {_pos = [_pos_center, _radius] call XfGetRanPointCircle};
				} else {
					_pos = _pos_center;
				};
				_units = [_pos, (_unit_array select 0), _newgroup] call x_makemgroup;
				_newgroup allowFleeing 0;
				if (!_do_patrol) then {
					_newgroup setCombatMode "YELLOW";
					_newgroup setFormation (["COLUMN","STAG COLUMN","WEDGE","ECH LEFT","ECH RIGHT","VEE","LINE","DIAMOND"] call XfRandomArrayVal);
					_newgroup setFormDir (floor random 360);
					_newgroup setSpeedMode "NORMAL";
				};
				_ret_grps set [count _ret_grps, _newgroup];
				if (_do_patrol) then {
					[_newgroup, _pos, [_pos_center, _radius], [5, 15, 30]] spawn XMakePatrolWPX;
				} else {
					[_newgroup, _pos_center] spawn XfTaskDefend;
				};
				extra_mission_remover_array = [extra_mission_remover_array , _units] call XfArrayPushStack;
			};
		};
	};
	_ret_grps
};

XCreateArmor = {
	private ["_numvehicles", "_radius", "_pos", "_nr", "_nrg", "_typenr", "_i", "_newgroup", "_reta"];
	_pos_center = _this select 6;
	_numvehicles = _this select 7;
	_radius = _this select 8;
	_do_patrol = (if (count _this == 10) then {_this select 9} else {false});
	if (_radius < 50) then {_do_patrol = false};
	_ret_grps = [];
	_pos = [];
	
	for "_nr" from 0 to 2 do {
		_nrg = _this select (1 + (_nr * 2));
		if (_nrg > 0) then {
			_typenr = _this select (_nr * 2);
			for "_i" from 1 to _nrg do {
				_newgroup = [d_side_enemy] call x_creategroup;
				if (_radius > 0) then {
					_pos = [_pos_center, _radius] call XfGetRanPointCircle;
					while {count _pos == 0} do {_pos = [_pos_center, _radius] call XfGetRanPointCircle};
				} else {
					_pos = _pos_center;
				};
				_unit_array = [_typenr, d_enemy_side] call x_getunitliste;
				_reta = [_numvehicles, _pos, (_unit_array select 1), _newgroup, 0,-1.111] call x_makevgroup;
				_newgroup allowFleeing 0;
				if (!_do_patrol) then {
					_newgroup setCombatMode "YELLOW";
					_newgroup setFormation (["COLUMN","STAG COLUMN","WEDGE","ECH LEFT","ECH RIGHT","VEE","LINE","DIAMOND"] call XfRandomArrayVal);
					_newgroup setFormDir (floor random 360);
					_newgroup setSpeedMode "NORMAL";
				};
				_ret_grps set [count _ret_grps, _newgroup];
				if (_do_patrol) then {[_newgroup, _pos, [_pos_center, _radius], [5, 15, 30]] spawn XMakePatrolWPX};
			};
		};
	};
	_ret_grps
};

XGuardWP = {
	private ["_ggrp"];
	_ggrp = _this;
	_ggrp setCombatMode "YELLOW";
	_ggrp setFormation (["COLUMN","STAG COLUMN","WEDGE","ECH LEFT","ECH RIGHT","VEE","LINE","FILE","DIAMOND"] call XfRandomArrayVal);
	_ggrp setFormDir (floor random 360);
	_ggrp setSpeedMode "NORMAL";
	_ggrp setBehaviour "SAFE";
};

XAttackWP = {
	private ["_ggrp","_gtarget_pos","_gwp"];
	_ggrp = _this select 0;
	_gtarget_pos = _this select 1;
	_ggrp setbehaviour "AWARE";
	_gwp = _ggrp addWaypoint [_gtarget_pos,30];
	_gwp setwaypointtype "SAD";
	_gwp setWaypointCombatMode "YELLOW";
	_gwp setWaypointSpeed "FULL";
};

XOutOfBounds = {
	private ["_vec", "_p_x", "_vehicle", "_p_y"];
	_vec = _this;
	_p_x = position _vehicle select 0;
	_p_y = position _vehicle select 1;
	if ((_p_x < 0 || _p_x > ((d_island_center select 0) * 2)) && (_p_y < 0 || _p_y > ((d_island_center select 1) * 2))) then {true} else {false}
};

// supports also patrols in square areas, including angle
XMakePatrolWPX = {
	private ["_grp", "_start_pos", "_wp_array", "_i", "_wp_pos", "_counter", "_wp", "_wppos", "_pos", "_cur_pos","_no_pos_found"];
	_grp = _this select 0;
	_start_pos = _this select 1;
	_wp_array = _this select 2;
	if (typeName _wp_array == "OBJECT") then {_wp_array = position _wp_array};
	if (typeName _wp_array != "ARRAY") exitWith {};
	if (typeName _start_pos == "OBJECT") then {_start_pos = position _start_pos};
	if (typeName _start_pos != "ARRAY") exitWith {};
	if (count _start_pos == 0) exitWith {};
	_timeout = if ((count _this) > 3) then {_this select 3} else {[]};
	_grp setBehaviour "SAFE";
	_cur_pos = _start_pos;
	_no_pos_found = false;
	for "_i" from 0 to (2 + (floor (random 3))) do {
		_wp_pos = switch (count _wp_array) do {
			case 2: {[_wp_array select 0, _wp_array select 1] call XfGetRanPointCircle};
			case 4: {[_wp_array select 0, _wp_array select 1, _wp_array select 2, _wp_array select 3] call XfGetRanPointSquare};
		};
		if (count _wp_pos == 0) exitWith {_no_pos_found = true};
		_counter = 0;
		while {_wp_pos distance _cur_pos < ((_wp_array select 1)/6) && _counter < 100} do {
			_wp_pos = switch (count _wp_array) do {
				case 2: {[_wp_array select 0, _wp_array select 1] call XfGetRanPointCircle};
				case 4: {[_wp_array select 0, _wp_array select 1, _wp_array select 2, _wp_array select 3] call XfGetRanPointSquare};
			};
			if (count _wp_pos == 0) exitWith {};
			_counter = _counter + 1;
		};
		if (count _wp_pos == 0) exitWith {_no_pos_found = true};
		_wp_pos = _wp_pos call XfWorldBoundsCheck;
		_cur_pos = _wp_pos;
		_wp = _grp addWaypoint [_wp_pos, 0];
		_wp setWaypointType "MOVE";
		_wp setWaypointCompletionRadius (0 + random 10);
		if (count _timeout > 0) then {_wp setWaypointTimeout _timeout};

		if (_i == 0) then {
			_wp setWaypointSpeed "LIMITED";
			_wp setWaypointFormation "STAG COLUMN";
		};
	};
	if (_no_pos_found) exitWith {
		_wp1 = _grp addWaypoint [_start_pos, 0];
		_wp1 setWaypointType "SAD";
	};
	_wp1 = _grp addWaypoint [_start_pos, 0];
	_wp1 setWaypointType "SAD";
	_wp1 setWaypointCompletionRadius (10 + random 10);
	if (count _timeout > 0) then {_wp1 setWaypointTimeout _timeout};
	_wp = _grp addWaypoint [_start_pos, 0];
	_wp setWaypointType "CYCLE";
	_wp setWaypointCompletionRadius (10 + random 10);
};

XfDelVecAndCrew = {{deleteVehicle _x} forEach ([[_this], crew _this] call XfArrayPushStack)};

XfPlacedObjKilled = {
	private "_val";
	_val = (_this select 0) getVariable "d_owner";
	if (!isNil "_val") then {
		["d_p_o_an", _val] call XNetCallEvent;
	};
};

XGetPlayerArray = {
	private ["_uid","_parray"];
	_uid = _this select 0;
	_parray = d_player_store getVariable _uid;
	if (!isNil "_parray") then {
		_parray set [4, (_this select 1)];
	};
};

XAddPlayerScore = {
	private ["_uid", "_score", "_pa"];
	_uid = _this select 0;_score = _this select 1;
	_pa = d_player_store getVariable _uid;
	if (!isNil "_pa") then {_pa set [3, _score]};
};

XGetAdminArray = {
	_p = d_player_store getVariable _this;
	if (isNil "_p") then {_p = []};
	["d_s_p_inf", _p] call XNetCallEvent;
};

XRemABox = {
	private ["_object","_i", "_box_a", "_pos","_boxes","_box_count"];
	diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"serverfunctions.sqf","XRemABox",_this];
	if (typename _this != "ARRAY") exitWith {diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"serverfunctions.sqf","XRemABox","Invalid parameter"];};
	_object = _this select 0;
	_boxes = ["d_ammo_boxes",[]] call XNetGetJIP;
	_box_count = ["ammo_boxes",1] call XNetGetJIP;
	for "_i" from 0 to (count _boxes - 1) do {
		_box_a = _boxes select _i;
		_pos = _box_a select 0;
		if (_pos distance _object < 5) then {
			// Removing a box
			diag_log Format["(%1)[%2]: %3 at %4 (%5)",diag_tickTime,"serverfunctions.sqf","Removing a box",_pos,(!isnil "_marker_name")];
			_boxes set [_i,-1];
			_box_count = _box_count - 1;
		};
	};
	_boxes = _boxes - [-1];
	for "_i" from 0 to (count d_check_boxes - 1) do {
		_box_a = d_check_boxes select _i;
		_pos = _box_a select 1;
		if (_pos distance _object < 1) then {
			d_check_boxes set [_i, -1];
		};
	};
	d_check_boxes = d_check_boxes - [-1];
	if (_box_count < 0) then { _box_count = 0; };
	["d_ammo_boxes",_boxes] call XNetSetJIP;
	["ammo_boxes",_box_count] call XNetSetJIP;
};

["FEAST", "FlagCarrierRU"] call XfStoreAdd;
["FWEST", "FlagCarrierUSA"] call XfStoreAdd;
["FGUER", "FlagCarrierGUE"] call XfStoreAdd;

XfGetEnemyFlagType = {("F" + d_enemy_side) call XfStoreGet};

XfGetOwnFlagType = {("F" + d_own_side) call XfStoreGet};

XfReturnVehicleTurrets = {
	/*
		File: fn_returnVehicleTurrets.sqf
		Author: Joris-Jan van 't Land

		Description:
		Function return the path to all turrets and sub-turrets in a vehicle.

		Parameter(s):
		_this select 0: vehicle config entry (Config)

		Returns:
		Array of Scalars and Arrays - path to all turrets
	*/
	if ((count _this) < 1) exitWith {[]};
	private ["_entry"];
	_entry = _this select 0;
	if ((typeName _entry) != (typeName configFile)) exitWith {[]};
	private ["_turrets", "_turretIndex"];
	_turrets = [];
	_turretIndex = 0;
	for "_i" from 0 to ((count _entry) - 1) do {
		private ["_subEntry"];
		_subEntry = _entry select _i;
		if (isClass _subEntry) then {
			private ["_hasGunner"];
			_hasGunner = [_subEntry, "hasGunner"] call XfReturnConfigEntry;
			if (!(isNil "_hasGunner")) then {
				if (_hasGunner == 1) then {
					_turrets set [count _turrets, _turretIndex];
					if (isClass (_subEntry >> "Turrets")) then {
						_turrets set [count _turrets, [_subEntry >> "Turrets"] call XfReturnVehicleTurrets];
					} else {
						_turrets set [count _turrets, []];
					};
				};
			};
			_turretIndex = _turretIndex + 1;
		};
	};
	_turrets
};

XfReturnConfigEntry = {
	/*
		File: returnConfigEntry.sqf
		Author: Joris-Jan van 't Land

		Description:
		Explores parent classes in the run-time config for the value of a config entry.
		
		Parameter(s):
		_this select 0: starting config class (Config)
		_this select 1: queried entry name (String)
		
		Returns:
		Number / String - value of the found entry
	*/
	if ((count _this) < 2) exitWith {nil};
	private ["_config", "_entryName"];
	_config = _this select 0;
	_entryName = _this select 1;
	if ((typeName _config) != (typeName configFile)) exitWith {nil};
	if ((typeName _entryName) != (typeName "")) exitWith {nil};
	private ["_entry", "_value"];
	_entry = _config >> _entryName;
	if (((configName (_config >> _entryName)) == "") && (!((configName _config) in ["CfgVehicles", "CfgWeapons", ""]))) then {
		[inheritsFrom _config, _entryName] call XfReturnConfigEntry;
	} else {
		if (isNumber _entry) then {
			_value = getNumber _entry;
		} else {
			if (isText _entry) then {_value = getText _entry};
		};
	};
	if (isNil "_value") exitWith {nil};
	_value
};

XfSelectCrew = {
	/*
		File: selectCrew.sqf
		Author: Joris-Jan van 't Land

		Description:
		Return an appropriate crew type for a certain vehicle.
		
		Parameter(s):
		_this select 0: side (Side)
		_this select 1: vehicle config entry (Config)
		
		Returns:
		Array - crew type, cargo types (array) for Wheeled APCs
	*/
	if ((count _this) < 2) exitWith {};
	private ["_side", "_entry", "_type"];
	_side = _this select 0;
	_entry = _this select 1;
	_type = _this select 2;
	if ((typeName _side) != (typeName sideEnemy)) exitWith {""};
	if ((typeName _entry) != (typeName configFile)) exitWith {""};
	private ["_crew", "_typcargo","_override"];
	_crew = "";
	_typcargo = [];
	_crew = getText (_entry >> "crew");
	switch (_side) do {
		case east: {if (!isnil "d_crew_E") then { _crew = d_crew_E call XfRandomArrayVal;};};
		case west: {if (!isnil "d_crew_W") then { _crew = d_crew_W call XfRandomArrayVal;};};
		case resistance: {if (!isnil "d_crew_G") then { _crew = d_crew_G call XfRandomArrayVal;};};
		default { if (!isnil "d_crew_C") then { _crew = d_crew_C call XfRandomArrayVal;};};
	};
	if (_crew == "") then {
		switch (_side) do {
			case west: {_crew = "USMC_Soldier_Crew"};
			case east: {_crew = "RU_Soldier_Crew"};
			case resistance: {_crew = "GUE_Soldier_Sab"};
			default {_crew = "Worker1"};
		};
	} else {
		if (_type isKindOf "Car" || _type isKindOf "Tracked_APC") then {
			_typcargo = (getArray (_entry >> "typicalCargo")) - [_crew,"Soldier"];
			_override = [];
			switch (_side) do {
				case east: {if (!isnil "d_cargo_crew_override_E") then { _override = d_cargo_crew_override_E;};};
				case west: {if (!isnil "d_cargo_crew_override_W") then { _override = d_cargo_crew_override_W;};};
				case resistance: {if (!isnil "d_cargo_crew_override_G") then { _override = d_cargo_crew_override_G;};};
				default { if (!isnil "d_cargo_crew_override_C") then { _override = d_cargo_crew_override_C;};};
			};
			if ((count _override > 0) && (count _typcargo > 0)) then {
				for [{_i = 0},{_i < count _typcargo},{_i = _i + 1}] do {
					_typcargo set [ _i, (_override call XfRandomArrayVal)];
				};
			};
		};
	};
	[_crew, _typcargo]
};

XCreateDroppedBox = {
	private ["_vec","_the_box_pos","_cbox", "_boxes","_marker","_box_type","_box_side","_new_box"];
	diag_log Format["(%1)[%2]: %3 %4",diag_tickTime,"serverfunctions.sqf", "XCreateDroppedBox", _this];
	_the_box_pos = _this select 0;
	_vec = _this select 1;
	_marker = "";
	_box_type= d_default_ammo_box;
	_box_side = d_own_side;
	if (count _this > 2) then {_marker = _this select 2};
	if (count _this > 3) then {_box_side = _this select 3};
	if (count _this > 4) then {_box_type = _this select 4};
	["ammo_boxes",(["ammo_boxes",0] call XNetGetJIP) + 1] call XNetSetJIP;
	_cbox = [_vec, _the_box_pos];
	d_check_boxes set [count d_check_boxes, _cbox];
	_new_box = [_the_box_pos,_vec,_marker,_box_side,_box_type];
	_boxes = (["d_ammo_boxes",[]] call XNetGetJIP);
	_boxes set [count _boxes, _new_box];
	["d_ammo_boxes",_boxes] call XNetSetJIP;
	diag_log Format["(%1)[%2]: %3 (%4): %5",diag_tickTime,"servefunctions.sqf","Adding a box to the array!", count _boxes,_new_box];
};

XDamHandler = {
	private "_d_dam";
	(_this select 0) allowDamage (_this select 1);
	if (_this select 1) then {
		_d_dam = (["d_dam",[]] call XNetGetJIP);
		if ((_this select 0) in _d_dam) then {
			_d_dam = _d_dam - [_this select 0];
			_d_dam = _d_dam - [objNull];
			["d_dam",_d_dam] call XNetSetJIP;
		};
	} else {
		_d_dam = (["d_dam",[]] call XNetGetJIP);
		if (!((_this select 0) in _d_dam)) then {
			_d_dam set [count _d_dam, _this select 0];
			_d_dam = _d_dam - [objNull];
			["d_dam",_d_dam] call XNetSetJIP;
		};
	};
};

XfGetLinePoints = {
	private ["_startpoint", "_endpoint", "_radius", "_ret", "_curpoint", "_wpdist", "_wpangle", "_x1", "_y1"];
	_startpoint = _this select 0;
	_endpoint = _this select 1;
	_radius = if (count _this > 2) then {_this select 2} else {8000};
	if (typeName _startpoint == "OBJECT") then {_startpoint = position _startpoint};
	if (typeName _endpoint == "OBJECT") then {_endpoint = position _endpoint};
	_ret = [];
	_curpoint = _startpoint;
	_wpdist = _curpoint distance _endpoint;
	if (_wpdist > _radius) then {
		_wpangle = [_curpoint, _endpoint] call XfDirTo;
		while {_wpdist > _radius} do {
			_x1 = (_curpoint select 0) + (_radius * sin _wpangle);
			_y1 = (_curpoint select 1) + (_radius * cos _wpangle);
			_curpoint = [_x1, _y1, 0];
			_wpdist = _curpoint distance _endpoint;
			_ret set [count _ret, _curpoint];
		};
	};
	_ret set [count _ret, [_endpoint select 1, _endpoint select 2, 0]];
	_ret
};

XfAirMarkerMove = {
	private ["_vec", "_markern","_marker_text"];
	_marker_color = "ColorRed";
	_marker_text = "U.A.C.";
	_marker_icon = "Air";
	_control_variable = "WithAntiAirRadar";
	if (typeName _this == "ARRAY") then {
		_vec = _this select 0;
		if (count _this > 1) then {	_marker_text = _this select 1; };
		if (count _this > 2) then {	_marker_color = _this select 2; };
		if (count _this > 3) then {	_marker_icon = _this select 3; };
	} else {
		_vec = _this;
	};
	sleep (10 + random(10));
	if (!isNull _vec && alive _vec && canMove _vec) then {
		_markern = str(_vec);
		// Marker starts invisible
		[_markern, [0,0,0],"ICON",_marker_color,[0.7,0.7],_marker_text,0,_marker_icon,"",0] call XfCreateMarkerGlobal;
		while {!isNull _vec && alive _vec && canMove _vec } do {
			_show = missionNamespace getVariable _control_variable;
			if (_show) then {
				_markern setMarkerPos getPosASL _vec;
				_markern setMarkerAlpha 1;
			} else {
				_markern setMarkerAlpha 0;
				sleep 10;
			};
			sleep (3 + random 3);
		};
		deleteMarker _markern;
	};
};

// [_grp, "U.A.C","ColorRed","Air","WithAntiAirRadar"] spawn XfGroupMarkerMove;
XfGroupMarkerMove = {
	private ["_grp", "_markern","_marker_text","_leader","_marker_icon","_control_variable"];
	_marker_color = "ColorRed";
	_marker_text = "U.A.C.";
	_marker_icon = "Air";
	_control_variable = "WithAntiAirRadar";
	if (typeName _this == "ARRAY") then {
		_grp = _this select 0;
		if (count _this > 1) then {	_marker_text = _this select 1; };
		if (count _this > 2) then {	_marker_color = _this select 2; };
		if (count _this > 3) then {	_marker_icon = _this select 3; };
		if (count _this > 4) then {	_control_variable = _this select 4; };
	} else {
		_grp = _this;
	};
	sleep (10 + random(10));
	_leader = leader _grp;
	if (!isNull _leader && alive _leader && canMove _leader) then {
		_markern = str(_grp);
		// Marker starts invisible
		[_markern, [0,0,0],"ICON",_marker_color,[0.7,0.7],_marker_text,0,_marker_icon,"",0.00000001] call XfCreateMarkerGlobal;
		while {!isNull _leader && alive _leader && canMove _leader } do {
			_show = missionNamespace getVariable _control_variable;
			if (isNil "_show") then {_show = false;};
			if (_show) then {
				_markern setMarkerPos getPosASL _leader;
				_markern setMarkerAlpha 1;
			} else {
				_markern setMarkerAlpha 0;
				sleep 20;
			};
			sleep (3 + random 3);
			_leader = leader _grp;
		};
		deleteMarker _markern;
	};
};
